/*
 * dataset.h
 *
 *  Created on: Feb 28, 2011
 *      Author: tqlong
 */

#ifndef DATASET_H_
#define DATASET_H_

#include <vector>
#include <iostream>
#include <fstream>

template <typename T>
class Example : public T
{
public:
  typedef T                   vec_type;
protected:
  template <typename U> friend class Dataset;
  //vec_type x_;
  double y_;
public:
  Example(const vec_type& x, double y) : vec_type(x), y_(y) {}
  Example(int dim = 1) : vec_type(dim) {}
  const vec_type& x() const { return (const vec_type&)(*this); }
  double y() const { return y_; }

  void save(const std::string& fname);
  void save(std::ostream& f);
  bool load(const std::string& fname);
  bool load(std::istream& f);
};

//template <typename T>
//class Example
//{
//public:
//  typedef T                   vec_type;
//protected:
//  template <typename U> friend class Dataset;
//  vec_type x_;
//  double y_;
//public:
//  Example(const vec_type& x, double y) : x_(x), y_(y) {}
//  Example(int dim = 1) : x_(dim) {}
//  const vec_type& x() const { return x_; }
//  double y() const { return y_; }
//
//  void save(const std::string& fname);
//  void save(std::ostream& f);
//  bool load(const std::string& fname);
//  bool load(std::istream& f);
//};

template <typename T>
class Dataset
{
public:
  typedef T               vec_type;
  typedef Example<T>      example_type;
protected:
  std::vector<example_type> p_;
  int dim_;
  std::string fname_;
  std::ifstream f_;
  bool bias_;
  std::vector<int> shuffle_idx_;
public:
  Dataset(const std::string& fname, bool bias_ele = true); // online version
  Dataset() {}  // batch version
  ~Dataset() { f_.close(); }

  void save(const std::string& fname);
  void save(std::ostream& f);
  void load(const std::string& fname, bool bias_ele = true);
  void load(std::istream& f, bool bias_ele = true);
  bool next();
  void restart();
  void generate(int n, int d, double noise = 0.0);
  void shuffle();

  const int dim() const { return dim_; }
  const int n() const { return p_.size(); }
  const vec_type& x(int i = 0) const { return shuffle_idx_.size() > 0 ? p_[shuffle_idx_[i]].x() : p_[i].x(); }
  double y(int i = 0) const { return shuffle_idx_.size() > 0 ? p_[shuffle_idx_[i]].y() : p_[i].y(); }
};

#include "dataset_impl.h"

#endif /* DATASET_H_ */
